import { allStock } from './stockCodeList';
import axios from 'axios';
import { RowDataPacket } from 'mysql2/promise';
const fs = require('fs');
const pino = require('pino');

const puppeteer = require('puppeteer-core');

import path from 'path';

import mysql from 'mysql2/promise';
import { promisify } from 'util';
// 创建一个可写流，指定日志文件的路径
// 使用 __dirname 获取当前文件的目录并构建日志文件的绝对路径
const logFilePath = path.join(__dirname, '../../my-log-file.log');

// 创建一个可写流，指定日志文件的路径
const logStream = fs.createWriteStream(logFilePath, { flags: 'a' });

// 添加错误监听
logStream.on('error', (err: any) => {
  console.error('Log stream encountered an error:', err);
});

// 创建一个 Pino 实例，将日志输出到文件
const logger = pino(logStream);
type Stock = {
  code: string;
  name: string;
};


/**
 * 数据库查询通用方法（修正类型定义）
 * @param sql SQL查询语句
 * @param params 查询参数数组
 * @returns 查询结果（明确为行数据数组）
 */
async function queryDatabase(sql: string, params: any[] = []): Promise<RowDataPacket[]> {
  let connection: mysql.Connection | null = null;
  try {
    connection = await mysql.createConnection({
      host: 'localhost',
      port: 3306,
      user: 'ubuntu',
      password: '5600619611',
      database: 'data',
    });

    // 执行查询并明确类型为RowDataPacket数组
    const [rows] = await connection.execute<RowDataPacket[]>(sql, params);
    return rows;
  } catch (error) {
    console.error('数据库查询失败:', error);
    logger.error(`SQL查询错误: ${sql}, 参数: ${JSON.stringify(params)}, 错误: ${error}`);
    throw error;
  } finally {
    if (connection) {
      try {
        await connection.end();
      } catch (closeError) {
        console.error('关闭数据库连接失败:', closeError);
      }
    }
  }
}

async function makeUrlsLoop() {
  // 使用正则表达式匹配股票代码和名称
  // const regex = /([\u4e00-\u9fa5]+)\((\d+)\)/g;
  const regex = /(.+?)\((\d+)\)/g;
  const stockArray = [];
  let match;

  while ((match = regex.exec(allStock)) !== null) {
    const [, name, code] = match;
    stockArray.push({ code, name });
  }

  if (stockArray && stockArray.length) {
    const failedStocks: Stock[] = []; // 用于存储失败的股票

    async function processStocks(stockArray: any[]) {
      let index = 0;

      async function processNext() {
        if (index < stockArray.length) {
          const element = stockArray[index];
          const result = await getStockData(element);
          if (result !== `${element.code}获取成功`) {
            failedStocks.push(element); // 如果获取失败，将该股票添加到失败列表
          }
          // 对失败的股票进行再次尝试
          const stillFailedStocks: Stock[] = [];
          for (let failedStock of failedStocks) {
            const retryResult = await getStockData(failedStock);
            if (retryResult !== `${failedStock.code}获取成功`) {
              stillFailedStocks.push(failedStock); // 如果再次获取失败，将该股票添加到仍然失败的列表
            }
          }

          // 如果仍有失败的股票，记录到日志
          if (stillFailedStocks.length > 0) {
            logger.error(
              `仍然获取失败的股票: ${JSON.stringify(stillFailedStocks)}`,
            );
          }
          index++;
          // console.log('code: ',element.code)
          setTimeout(processNext, 5000); // 每5秒运行一次
        }
      }

      processNext();
    }

    processStocks(stockArray);
  }

  return stockArray;
}
async function getStockData(params: Stock) {
  let code: string = params.code;
  try {
    let url_ = `https://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&pointType=string&group=quotation_kline_ab&query=${code}&code=${code}&market_type=ab&newFormat=1&name=null&is_kc=0&ktype=day&finClientType=pc&finClientType=pc`;
    // 发起 HTTP GET 请求logger.info
    // 添加自定义的 headers
    const headers = {
      'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    };
    const response = await axios.get(url_, { headers });
    // 获取响应数据
    const data = response.data;
    const {
      Result: {
        newMarketData: { marketData },
      },
    } = data;
    if (marketData) {
      const now = new Date();
      const filename = path.join(
        'txtdata',
        `${now.getFullYear()}${(now.getMonth() + 1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}_${code}_股票数据.txt`,
      );
      // Ensure folder exists
      fs.promises
        .mkdir(path.dirname(filename), { recursive: true })
        .then(() => {
          // Write to file
          fs.promises
            .writeFile(filename, JSON.stringify(marketData), 'utf-8')
            .then(() => console.log('File written successfully:', filename))
            .catch((writeError: any) =>
              logger.info('Error creating directory:', writeError),
            );
        })
        .catch((mkdirError: any) =>
          logger.info('Error creating directory:', mkdirError),
        );
      return `${code}获取成功`;
    } else {
      logger.info('Error 获取股票数据失败:', code);
    }
    return `${code}获取失败`;
  } catch (error) {
    console.error('Error fetching stock data:', error);
    logger.info('Error 获取股票数据失败:', code);
  }
}
function containsNumber(inputString: string) {
  // 使用正则表达式匹配数字
  // \d 表示任意数字
  // + 表示匹配一个或多个数字
  // 如果字符串中包含数字，则返回 inputString ，否则返回'--'
  return /\d+/.test(inputString) ? inputString : '--';
}
// 定义一个函数，接受一个字符串作为参数
function removeNonNumericElements(inputString: string) {
  // 使用正则表达式匹配数字
  // \d 表示任意数字
  // g 表示全局匹配，即匹配所有数字
  const numbers = inputString.match(/\d+/g);

  // 如果数字数组存在并且不为空
  if (numbers && numbers.length > 0) {
    // 将数组中的数字连接成一个字符串并返回
    return numbers.join('');
  } else {
    // 如果没有找到数字，返回 false
    return false;
  }
}
async function readFileFromDir(your_file_path: string) {
  // 读取文件内容
  const fileContent = fs.readFileSync(your_file_path, 'utf8');

  let tempArray = fileContent.split(';');
  let resArray: any = [];
  if (tempArray && tempArray.length) {
    tempArray.forEach((element: any, i: number) => {
      // 根据逗号分割字符串
      const splitContent = element.split(',');

      // 解析日期格式
      const [timestamp, date] = [splitContent[0], splitContent[1]];
      // 提取所需数据
      const data = {
        stock_code: your_file_path.split('_')[2],
        timestamp: timestampToMySQLDate(
          Number(removeNonNumericElements(timestamp)),
        ),
        time: date,
        open: Number(containsNumber(splitContent[2])) ?? null,
        close: Number(containsNumber(splitContent[3])) ?? null,
        volume: Number(containsNumber(splitContent[4])) ?? null,
        high: Number(containsNumber(splitContent[5])) ?? null,
        low: Number(containsNumber(splitContent[6])) ?? null,
        amount: Number(containsNumber(splitContent[7])) ?? null,
        range: !Number.isNaN(Number(containsNumber(splitContent[8])))
          ? Number(containsNumber(splitContent[8]))
          : null,
        ratio: !Number.isNaN(Number(containsNumber(splitContent[9])))
          ? Number(containsNumber(splitContent[9]))
          : null,
        turnoverratio: !Number.isNaN(Number(containsNumber(splitContent[10])))
          ? Number(containsNumber(splitContent[10]))
          : null,
        preClose: !Number.isNaN(Number(containsNumber(splitContent[11])))
          ? Number(containsNumber(splitContent[11]))
          : null,
        ma5avgprice: !Number.isNaN(Number(containsNumber(splitContent[12])))
          ? Number(containsNumber(splitContent[12]))
          : null,
        ma5volume: !Number.isNaN(Number(containsNumber(splitContent[13])))
          ? Number(containsNumber(splitContent[13]))
          : null,
        ma10avgprice: !Number.isNaN(Number(containsNumber(splitContent[14])))
          ? Number(containsNumber(splitContent[14]))
          : null,
        ma10volume: !Number.isNaN(Number(containsNumber(splitContent[15])))
          ? Number(containsNumber(splitContent[15]))
          : null,
        ma20avgprice: !Number.isNaN(Number(containsNumber(splitContent[16])))
          ? Number(containsNumber(splitContent[16]))
          : null,
        ma20volume: !Number.isNaN(Number(containsNumber(splitContent[17])))
          ? Number(containsNumber(splitContent[17]))
          : null,
      };
      resArray.push(data);
    });
  }
  return resArray;
}
function timestampToMySQLDate(unixTimestamp: number) {
  const date = new Date(unixTimestamp * 1000);
  return date.toLocaleString().slice(0, 19).replace('T', ' ');
}
// --------------公共变量---------------
const batchSize: number = 50000; // 每批次的大小
let batchData: any = []; // 用于累积批量数据的数组
let connection: mysql.Connection;

async function insertBatchData(connection: mysql.Connection): Promise<void> {
  if (batchData.length === 0) return;

  try {
    const insertQuery = `INSERT INTO stock_2024_data (
      stock_code, timestamp, time, open, close, volume, high, low,
      amount, \`range\`, ratio, turnoverratio, preClose, ma5avgprice,
      ma5volume, ma10avgprice, ma10volume, ma20avgprice, ma20volume
      ) VALUES ?`;
    const [insertResult]: any = await connection.query(insertQuery, [
      batchData,
    ]);
    console.log(`Inserted ${insertResult.affectedRows} rows successfully.`);
  } catch (error) {
    console.error('An error occurred during the batch insert:', error);
  }

  batchData = []; // 清空批量数据数组，为下一批次做准备
}

async function insertDataToMysql(
  event: Electron.IpcMainEvent,
  arg: any,
  batchSize: number = 50000,
) {
  const readdir = promisify(fs.readdir);
  const readFile = promisify(fs.readFile);
  const directoryPath = path.join('txtdata');
  // console.log(directoryPath, 'directoryPath-20240121');
  let fileNames;
  let fileContentArray: any = [];
  try {
    fileNames = await readdir(directoryPath);
  } catch (e) {
    console.log('e', e);
  }
  if (fileNames === undefined) {
    console.log('undefined');
  } else {
    const connection = await mysql.createConnection({
      host: '',
      user: 'zsy',
      password: '5600619611',
      database: 'gupiao',
      // Other options such as port, etc.
    });
    let batchCounter = 0;
    try {
      for (let index = 0; index < fileNames.length; index++) {
        let progressNum: number = ((index + 1) / fileNames.length) * 100;
        event.sender.send('data-insert-progress', Number(progressNum));
        const element = fileNames[index];
        const filePath: any = `${directoryPath}/${element}`;
        fileContentArray = await readFileFromDir(filePath);
        // 将对象数组转换为二维数组
        const dataToInsert = fileContentArray.map(
          (obj: {
            stock_code: any;
            timestamp: any;
            time: any;
            open: any;
            close: any;
            volume: any;
            high: any;
            low: any;
            amount: any;
            range: any;
            ratio: any;
            turnoverratio: any;
            preClose: any;
            ma5avgprice: any;
            ma5volume: any;
            ma10avgprice: any;
            ma10volume: any;
            ma20avgprice: any;
            ma20volume: any;
          }) => [
            obj.stock_code,
            obj.timestamp,
            obj.time,
            obj.open,
            obj.close,
            obj.volume,
            obj.high,
            obj.low,
            obj.amount,
            obj.range,
            obj.ratio,
            obj.turnoverratio,
            obj.preClose,
            obj.ma5avgprice,
            obj.ma5volume,
            obj.ma10avgprice,
            obj.ma10volume,
            obj.ma20avgprice,
            obj.ma20volume,
          ],
        );
        // if (index === 1) {
        //   console.log(dataToInsert[0]);
        // }
        try {
          dataToInsert.forEach((ele: any) => {
            batchData.push(ele);
          });
          if (batchData.length >= batchSize) {
            await insertBatchData(connection);
          }
          // const [insertResult] : any = await connection.query(insertQuery, [dataToInsert]);
          // console.log(`Inserted ${insertResult.affectedRows} rows successfully.`);
        } catch (error) {
          console.error(
            'An error occurred during the insert operation:',
            error,
          );
        } finally {
        }
      }
      // 处理剩余的数据（如果有）
      await insertBatchData(connection);
    } catch (error) {
    } finally {
      await connection.end();
      return;
    }
  }
}
async function getHousePrice(params: any) {
  return {
    message: '获取房价ok',
  };
}

// 创建一个 sleep 函数，用于暂停执行
const sleep = (ms: number | undefined) =>
  new Promise((resolve) => setTimeout(resolve, ms));

// 定义一个函数来处理页面内容的保存和翻页
const processPage = async (
  page: {
    title: () => any;
    evaluate: (
      arg0: { (): string; (selector: any): any },
      arg1: string | undefined,
    ) => any;
    $: (arg0: string) => any;
    waitForNavigation: (arg0: { waitUntil: string }) => any;
  },
  folderPath: string,
  url: string | number | URL | undefined,
  pageIndex = 1,
) => {
  // 获取页面标题，用作文件名
  const pageTitle = await page.title();
  const safePageTitle = pageTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase();

  // 直接获取页面上的文本内容
  const pageText: any = await page?.evaluate(
    () => document.documentElement.innerText,
  );

  // 将内容追加写入文件
  const filePath = path.join(folderPath, `page_.txt`);
  fs.appendFileSync(filePath, pageText);

  console.log(`内容添加到 ${filePath}`);

  const nextPageHref = await page.evaluate(() => {
    // 使用 Array.from 将 NodeList 转换为数组
    const aHrefs = Array.from(document.getElementsByTagName('a'));
    console.log(aHrefs, 'ahrefs-20240815');

    let nextPageButton = null;

    aHrefs.forEach((ele) => {
      console.log(ele, 'ellllllllllllllllllllllllllllllllllllllllllllllllllll');
      if (ele.innerText === '下一页') {
        nextPageButton = ele.getAttribute('href');
      }
    });

    return nextPageButton;
  });

  console.log(
    nextPageHref,
    'nextPageHrefnextPageHrefnextPageHrefnextPageHrefnextPageHrefnextPageHref-20240815',
  );
  if (nextPageHref) {
    const fullNextPageUrl = new URL(nextPageHref, url).href; // 使用 URL 对象来拼接完整 URL
    console.log('Navigating to:', fullNextPageUrl);
    await page.goto(fullNextPageUrl);

    sleep(5);

    // 递归调用 processPage 来处理新的页面
    await processPage(page, folderPath, url, pageIndex + 1);
  } else {
    console.log('No more pages to process.');
  }
};

// 主函数
const collectLianJiaData = async () => {
  const chromePath = path.join(
    'C:',
    'Program Files',
    'Google',
    'Chrome',
    'Application',
    'chrome.exe',
  );
  const url = 'https://sy.lianjia.com/ershoufang/heping1/';

  console.log('Launching browser...');
  console.log(`Chrome path: ${chromePath}`);

  const browser = await puppeteer.launch({
    executablePath: chromePath,
    headless: false, // 关闭无头模式
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  });

  const page = await browser.newPage();

  // 设置用户代理
  await page.setUserAgent(
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
  );

  // 设置额外的浏览器头
  await page.setExtraHTTPHeaders({
    'Accept-Language': 'en-US,en;q=0.9',
  });

  // 创建相对路径的文件夹
  const folderPath = path.join(__dirname, '..', '..', 'txtHousePriceData');
  if (!fs.existsSync(folderPath)) {
    fs.mkdirSync(folderPath, { recursive: true });
  }

  try {
    console.log(`Navigating to ${url}...`);
    await page.goto(url);
    console.log('Navigation completed.');

    // 处理当前页面并递归处理所有后续页面
    await processPage(page, folderPath, url);
  } catch (err) {
    console.error('Error during navigation:', err);
  } finally {
    await browser.close();
    console.log('Browser closed.');
  }
};

// 测试数据库连接函数
async function testDatabaseConnection() {
  try {
    const connection = await mysql.createConnection({
      host: 'localhost',
      port: 3306,
      user: 'ubuntu',
      password: '5600619611',
      database: 'data',
    });

    console.log('OKOKOK');

    // 测试连接
    await connection.ping();

    // 关闭连接
    await connection.end();

    return { success: true, message: '数据库连接成功' };
  } catch (error) {
    console.error('数据库连接失败:', error);
    throw error;
  }
}

// 创建股票数据表函数
async function createStockDataTable() {
  try {
    const connection = await mysql.createConnection({
      host: 'localhost',
      port: 3306,
      user: 'ubuntu',
      password: '5600619611',
      database: 'data',
    });

    // 检查表是否已存在
    const [tables] = await connection.query("SHOW TABLES LIKE 'stock_data'");

    if (Array.isArray(tables) && tables.length > 0) {
      // 如果表已存在，先删除它
      console.log('表已存在，正在删除旧表...');
      await connection.query('DROP TABLE stock_data');
      console.log('旧表删除成功');
    }

    // 创建新表
    const createTableSQL = `
      CREATE TABLE stock_data (
        id INT AUTO_INCREMENT PRIMARY KEY,
        code VARCHAR(10) NULL,
        timestamp BIGINT NULL,
        date DATE NULL,
        open DECIMAL(18, 4) NULL,
        close DECIMAL(18, 4) NULL,
        volume BIGINT NULL,
        high DECIMAL(18, 4) NULL,
        low DECIMAL(18, 4) NULL,
        amount DECIMAL(18, 4) NULL,
        change_amount DECIMAL(10, 4) NULL,
        change_percent DECIMAL(10, 4) NULL,
        turnover_ratio DECIMAL(10, 4) NULL,
        prev_close DECIMAL(18, 4) NULL,
        ma5_price DECIMAL(18, 4) NULL,
        ma5_volume BIGINT NULL,
        ma10_price DECIMAL(18, 4) NULL,
        ma10_volume BIGINT NULL,
        ma20_price DECIMAL(18, 4) NULL,
        ma20_volume BIGINT NULL,
        UNIQUE KEY(date, code)  -- 防止重复插入同一天同一股票的数据
      )
    `;

    await connection.query(createTableSQL);

    // 验证表结构
    await checkTableStructure(connection);

    await connection.end();

    return { success: true, message: '表创建成功', exists: false };
  } catch (error) {
    console.error('创建表失败:', error);
    throw error;
  }
}

// 检查表结构函数
async function checkTableStructure(connection: mysql.Connection) {
  try {
    console.log('检查表结构...');

    // 查看表结构
    const [columns] = await connection.query('DESCRIBE stock_data');
    console.log('表字段结构:', columns);

    // 查看索引
    const [indexes] = await connection.query('SHOW INDEX FROM stock_data');
    console.log('表索引结构:', indexes);

    // 查看创建表的SQL
    const [createTable] = await connection.query(
      'SHOW CREATE TABLE stock_data',
    );
    console.log('创建表SQL:', createTable[0]['Create Table']);
  } catch (error) {
    console.error('检查表结构失败:', error);
  }
}

// 全局变量存储解析后的数据
let parsedStockData: any[] = [];

// 读取数据文件函数
async function readDataFiles() {
  try {
    // 内存监控
    const startMemory = process.memoryUsage();
    console.log('开始读取数据文件，初始内存使用:', {
      heapUsed: Math.round(startMemory.heapUsed / 1024 / 1024) + 'MB',
      heapTotal: Math.round(startMemory.heapTotal / 1024 / 1024) + 'MB',
      external: Math.round(startMemory.external / 1024 / 1024) + 'MB',
    });

    const { dialog } = require('electron');
    const fs = require('fs').promises;
    const path = require('path');

    // 打开文件夹选择对话框
    const result = await dialog.showOpenDialog({
      properties: ['openDirectory'],
      title: '选择包含股票数据文件的文件夹',
    });

    if (result.canceled || result.filePaths.length === 0) {
      return { success: false, message: '未选择文件夹' };
    }

    const folderPath = result.filePaths[0];
    console.log('选择的文件夹路径:', folderPath);

    // 读取文件夹中的所有文件
    const files = await fs.readdir(folderPath);
    const dataFiles = files.filter(
      (file: string) => file.endsWith('.txt') || file.endsWith('.csv'),
    );

    if (dataFiles.length === 0) {
      return { success: false, message: '文件夹中没有找到数据文件' };
    }

    console.log(`找到 ${dataFiles.length} 个数据文件`);

    // 清空之前的数据
    parsedStockData = [];

    // 分批处理文件，避免内存溢出
    const batchSize = 100; // 每次处理100个文件
    let totalProcessedFiles = 0;
    let totalParsedRecords = 0;

    for (let i = 0; i < dataFiles.length; i += batchSize) {
      const batch = dataFiles.slice(i, i + batchSize);
      console.log(
        `正在处理批次 ${Math.floor(i / batchSize) + 1}/${Math.ceil(dataFiles.length / batchSize)}`,
      );

      // 处理当前批次的文件
      for (const file of batch) {
        try {
          const filePath = path.join(folderPath, file);
          console.log(`正在解析文件: ${file}`);

          // 检查文件大小，如果太大就跳过
          const stats = await fs.stat(filePath);
          const fileSizeInMB = stats.size / (1024 * 1024);

          if (fileSizeInMB > 50) {
            // 跳过大于50MB的文件
            console.warn(
              `文件 ${file} 太大 (${fileSizeInMB.toFixed(2)}MB)，跳过处理`,
            );
            continue;
          }

          const fileContent = await fs.readFile(filePath, 'utf8');

          // 尝试解析为 JSON 格式
          let parsedData;
          try {
            parsedData = parseJsonStockDataFile(fileContent, file);
          } catch (jsonError) {
            // 如果不是 JSON 格式，尝试解析为普通文本格式
            parsedData = parseStockDataFile(fileContent, file);
          }

          // 限制每个文件的最大记录数，防止内存溢出
          if (parsedData.length > 10000) {
            console.warn(
              `文件 ${file} 记录数过多 (${parsedData.length})，只保留前10000条`,
            );
            parsedData = parsedData.slice(0, 10000);
          }

          parsedStockData.push(...parsedData);
          totalProcessedFiles++;
          totalParsedRecords += parsedData.length;

          // 定期清理内存
          if (totalParsedRecords % 10000 === 0) {
            console.log(
              `已处理 ${totalProcessedFiles} 个文件，解析 ${totalParsedRecords} 条记录`,
            );
            // 强制垃圾回收
            if (global.gc) {
              global.gc();
            }
          }
        } catch (error) {
          console.error(`解析文件 ${file} 失败:`, error);
          // 继续处理其他文件，不中断整个流程
        }
      }

      // 每批次处理后清理内存
      if (global.gc) {
        global.gc();
      }
    }

    console.log(
      `总共处理了 ${totalProcessedFiles} 个文件，解析 ${totalParsedRecords} 条数据记录`,
    );

    // 最终内存监控
    const endMemory = process.memoryUsage();
    console.log('读取数据文件完成，最终内存使用:', {
      heapUsed: Math.round(endMemory.heapUsed / 1024 / 1024) + 'MB',
      heapTotal: Math.round(endMemory.heapTotal / 1024 / 1024) + 'MB',
      external: Math.round(endMemory.external / 1024 / 1024) + 'MB',
      memoryIncrease:
        Math.round((endMemory.heapUsed - startMemory.heapUsed) / 1024 / 1024) +
        'MB',
    });

    return {
      success: true,
      message: `成功读取 ${totalProcessedFiles} 个文件，解析 ${totalParsedRecords} 条数据记录`,
      fileCount: totalProcessedFiles,
      dataCount: totalParsedRecords,
      data: parsedStockData.slice(0, 1000), // 只返回前1000条数据用于显示，避免内存问题
    };
  } catch (error) {
    console.error('读取数据文件失败:', error);
    throw error;
  }
}

// 解析股票数据文件
function parseStockDataFile(fileContent: string, fileName: string) {
  const lines = fileContent.split('\n').filter((line) => line.trim());
  const parsedData: any[] = [];

  // 从文件名提取股票代码
  const stockCode = extractStockCode(fileName);

  for (const line of lines) {
    try {
      // 假设数据格式为: timestamp,date,open,close,volume,high,low,amount,change_amount,change_percent,turnover_ratio,prev_close,ma5_price,ma5_volume,ma10_price,ma10_volume,ma20_price,ma20_volume
      const values = line.split(',').map((val) => val.trim());

      if (values.length >= 18) {
        const data = {
          code: stockCode,
          timestamp: parseInt(values[0]) || null,
          date: values[1] || null,
          open: parseFloat(values[2]) || null,
          close: parseFloat(values[3]) || null,
          volume: parseInt(values[4]) || null,
          high: parseFloat(values[5]) || null,
          low: parseFloat(values[6]) || null,
          amount: parseFloat(values[7]) || null,
          change_amount: parseFloat(values[8]) || null,
          change_percent: parseFloat(values[9]) || null,
          turnover_ratio: parseFloat(values[10]) || null,
          prev_close: parseFloat(values[11]) || null,
          ma5_price: parseFloat(values[12]) || null,
          ma5_volume: parseInt(values[13]) || null,
          ma10_price: parseFloat(values[14]) || null,
          ma10_volume: parseInt(values[15]) || null,
          ma20_price: parseFloat(values[16]) || null,
          ma20_volume: parseInt(values[17]) || null,
          source_file: fileName,
        };

        // 验证数据有效性
        if (data.date && data.open !== null && data.close !== null) {
          parsedData.push(data);
        }
      }
    } catch (error) {
      console.error(`解析行数据失败: ${line}`, error);
    }
  }

  return parsedData;
}

// 获取解析后的数据（供其他函数使用）
function getParsedStockData() {
  return parsedStockData;
}

// 从文件名提取股票代码
function extractStockCode(fileName: string): string {
  try {
    // 移除文件扩展名
    const nameWithoutExt = fileName.replace(/\.(txt|csv)$/i, '');

    // 查找6位连续数字
    const match = nameWithoutExt.match(/\d{6}/);

    if (match) {
      return match[0];
    }

    // 如果没有找到6位数字，尝试查找其他数字模式
    const anyMatch = nameWithoutExt.match(/\d+/);
    if (anyMatch) {
      // 如果找到的数字少于6位，前面补0
      const code = anyMatch[0].padStart(6, '0');
      return code;
    }

    // 如果都没有找到，返回文件名的一部分作为代码
    console.warn(`无法从文件名 ${fileName} 提取股票代码，使用默认值`);
    return '000000';
  } catch (error) {
    console.error(`提取股票代码失败: ${fileName}`, error);
    return '000000';
  }
}

// 解析 JSON 格式的股票数据文件
function parseJsonStockDataFile(fileContent: string, fileName: string) {
  try {
    const jsonData = JSON.parse(fileContent);
    const { marketData } = jsonData;

    if (!marketData) {
      console.error('文件中没有找到 marketData 字段');
      return [];
    }

    // 从文件名提取股票代码
    const stockCode = extractStockCode(fileName);

    // 按分号分割每一天的数据
    const dailyDataArray = marketData
      .split(';')
      .filter((data: string) => data.trim());
    const parsedData: any[] = [];

    // 限制最大处理记录数，防止内存溢出
    const maxRecords = 5000;
    const recordsToProcess = Math.min(dailyDataArray.length, maxRecords);

    if (dailyDataArray.length > maxRecords) {
      console.warn(
        `文件 ${fileName} 记录数过多 (${dailyDataArray.length})，只处理前 ${maxRecords} 条`,
      );
    }

    for (let i = 0; i < recordsToProcess; i++) {
      try {
        const dailyData = dailyDataArray[i];

        // 按逗号分割每个字段
        const values = dailyData.split(',').map((val: string) => val.trim());

        if (values.length >= 18) {
          // 辅助函数：安全解析数值
          const safeParseFloat = (val: string) => {
            if (!val || val === '--' || val === '' || val === 'null')
              return null;
            const parsed = parseFloat(val);
            return isNaN(parsed) ? null : parsed;
          };

          const safeParseInt = (val: string) => {
            if (!val || val === '--' || val === '' || val === 'null')
              return null;
            const parsed = parseInt(val);
            return isNaN(parsed) ? null : parsed;
          };

          const data = {
            code: stockCode,
            timestamp: safeParseInt(values[0]),
            date: values[1] && values[1] !== '--' ? values[1] : null,
            open: safeParseFloat(values[2]),
            close: safeParseFloat(values[3]),
            volume: safeParseInt(values[4]),
            high: safeParseFloat(values[5]),
            low: safeParseFloat(values[6]),
            amount: safeParseFloat(values[7]),
            change_amount: safeParseFloat(values[8]),
            change_percent: safeParseFloat(values[9]),
            turnover_ratio: safeParseFloat(values[10]),
            prev_close: safeParseFloat(values[11]),
            ma5_price: safeParseFloat(values[12]),
            ma5_volume: safeParseInt(values[13]),
            ma10_price: safeParseFloat(values[14]),
            ma10_volume: safeParseInt(values[15]),
            ma20_price: safeParseFloat(values[16]),
            ma20_volume: safeParseInt(values[17]),
            source_file: fileName,
          };

          // 验证数据有效性 - 只要有日期和基本价格数据就认为有效
          if (data.date && (data.open !== null || data.close !== null)) {
            parsedData.push(data);
          }
        }
      } catch (error) {
        console.error(`解析每日数据失败: ${dailyDataArray[i]}`, error);
        // 继续处理下一条记录，不中断整个文件
      }
    }

    return parsedData;
  } catch (error) {
    console.error(`解析 JSON 文件失败: ${fileName}`, error);
    return [];
  }
}

// 实验性插入数据（插入10条测试）
async function testInsertData(event: Electron.IpcMainEvent) {
  try {
    const connection = await mysql.createConnection({
      host: 'localhost',
      port: 3306,
      user: 'ubuntu',
      password: '5600619611',
      database: 'data',
    });

    // 获取解析后的数据
    const stockData = getParsedStockData();

    if (stockData.length === 0) {
      await connection.end();
      return { success: false, message: '没有可插入的数据，请先读取数据文件' };
    }

    // 只取前10条数据进行测试
    const testData = stockData.slice(0, 10);

    // 准备插入数据
    const insertData = testData.map((item: any) => [
      item.code,
      item.timestamp,
      item.date,
      item.open,
      item.close,
      item.volume,
      item.high,
      item.low,
      item.amount,
      item.change_amount,
      item.change_percent,
      item.turnover_ratio,
      item.prev_close,
      item.ma5_price,
      item.ma5_volume,
      item.ma10_price,
      item.ma10_volume,
      item.ma20_price,
      item.ma20_volume,
    ]);

    // 插入数据
    const insertQuery = `
      INSERT INTO stock_data (
        code, timestamp, date, open, close, volume, high, low, amount,
        change_amount, change_percent, turnover_ratio, prev_close,
        ma5_price, ma5_volume, ma10_price, ma10_volume, ma20_price, ma20_volume
      ) VALUES ?
    `;

    console.log('测试插入数据详情:', {
      dataCount: testData.length,
      sampleData: testData.slice(0, 2).map((item) => ({
        code: item.code,
        date: item.date,
        open: item.open,
        close: item.close,
      })),
    });

    const [result]: any = await connection.query(insertQuery, [insertData]);

    await connection.end();

    return {
      success: true,
      message: `实验性插入成功，插入了 ${result.affectedRows} 条数据`,
      insertedCount: result.affectedRows,
      testDataCount: testData.length,
    };
  } catch (error: any) {
    console.error('实验性插入失败，详细错误信息:', {
      message: error.message,
      code: error.code,
      errno: error.errno,
      sqlState: error.sqlState,
      sqlMessage: error.sqlMessage,
      sql: error.sql,
      stack: error.stack,
    });
    throw error;
  }
}

// 正式插入数据（插入所有数据）
async function formalInsertData(event: Electron.IpcMainEvent) {
  try {
    const connection = await mysql.createConnection({
      host: 'localhost',
      port: 3306,
      user: 'ubuntu',
      password: '5600619611',
      database: 'data',
    });

    // 获取解析后的数据
    const stockData = getParsedStockData();

    if (stockData.length === 0) {
      await connection.end();
      return { success: false, message: '没有可插入的数据，请先读取数据文件' };
    }

    console.log(`开始正式插入 ${stockData.length} 条数据`);

    // 分批插入数据，每批1000条
    const batchSize = 1000;
    let totalInserted = 0;
    let batchCount = 0;
    let errorCount = 0;
    let duplicateCount = 0;

    for (let i = 0; i < stockData.length; i += batchSize) {
      const batch = stockData.slice(i, i + batchSize);

      try {
        // 准备插入数据
        const insertData = batch.map((item: any) => [
          item.code,
          item.timestamp,
          item.date,
          item.open,
          item.close,
          item.volume,
          item.high,
          item.low,
          item.amount,
          item.change_amount,
          item.change_percent,
          item.turnover_ratio,
          item.prev_close,
          item.ma5_price,
          item.ma5_volume,
          item.ma10_price,
          item.ma10_volume,
          item.ma20_price,
          item.ma20_volume,
        ]);

        // 插入数据
        const insertQuery = `
          INSERT INTO stock_data (
            code, timestamp, date, open, close, volume, high, low, amount,
            change_amount, change_percent, turnover_ratio, prev_close,
            ma5_price, ma5_volume, ma10_price, ma10_volume, ma20_price, ma20_volume
          ) VALUES ?
        `;

        const [result]: any = await connection.query(insertQuery, [insertData]);
        totalInserted += result.affectedRows;
        batchCount++;

        // 更新进度
        const progress = Math.round(((i + batchSize) / stockData.length) * 100);
        event.sender.send('data-insert-progress', Math.min(progress, 100));

        console.log(
          `批次 ${batchCount}: 插入了 ${result.affectedRows} 条数据，总计 ${totalInserted} 条`,
        );
      } catch (batchError: any) {
        errorCount++;
        console.error(`批次 ${batchCount + 1} 插入失败:`, {
          error: batchError.message,
          code: batchError.code,
          errno: batchError.errno,
          sqlState: batchError.sqlState,
          sqlMessage: batchError.sqlMessage,
          sql: batchError.sql,
        });

        // 如果是重复键错误，尝试逐条插入
        if (batchError.code === 'ER_DUP_ENTRY') {
          console.log('检测到重复键错误，尝试逐条插入...');

          for (const item of batch) {
            try {
              const singleInsertQuery = `
                INSERT INTO stock_data (
                  code, timestamp, date, open, close, volume, high, low, amount,
                  change_amount, change_percent, turnover_ratio, prev_close,
                  ma5_price, ma5_volume, ma10_price, ma10_volume, ma20_price, ma20_volume
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
              `;

              const singleInsertData = [
                item.code,
                item.timestamp,
                item.date,
                item.open,
                item.close,
                item.volume,
                item.high,
                item.low,
                item.amount,
                item.change_amount,
                item.change_percent,
                item.turnover_ratio,
                item.prev_close,
                item.ma5_price,
                item.ma5_volume,
                item.ma10_price,
                item.ma10_volume,
                item.ma20_price,
                item.ma20_volume,
              ];

              await connection.query(singleInsertQuery, singleInsertData);
              totalInserted++;
            } catch (singleError: any) {
              if (singleError.code === 'ER_DUP_ENTRY') {
                duplicateCount++;
                console.log(`跳过重复数据: ${item.code} - ${item.date}`);
              } else {
                console.error(`单条数据插入失败:`, {
                  item: `${item.code} - ${item.date}`,
                  error: singleError.message,
                  code: singleError.code,
                });
              }
            }
          }
        } else {
          // 其他错误，记录详细信息
          console.error(`批次插入失败，错误详情:`, {
            batchStart: i,
            batchEnd: Math.min(i + batchSize, stockData.length),
            batchSize: batch.length,
            error: batchError.message,
            code: batchError.code,
            errno: batchError.errno,
            sqlState: batchError.sqlState,
            sqlMessage: batchError.sqlMessage,
          });
        }
      }
    }

    await connection.end();

    return {
      success: true,
      message: `正式插入完成，总共插入了 ${totalInserted} 条数据，跳过了 ${duplicateCount} 条重复数据，失败 ${errorCount} 个批次`,
      totalInserted,
      totalDataCount: stockData.length,
      batchCount,
      duplicateCount,
      errorCount,
    };
  } catch (error: any) {
    console.error('正式插入失败，详细错误信息:', {
      message: error.message,
      code: error.code,
      errno: error.errno,
      sqlState: error.sqlState,
      sqlMessage: error.sqlMessage,
      sql: error.sql,
      stack: error.stack,
    });
    throw error;
  }
}

// 获取重复数据函数
async function getDuplicateData() {
  try {
    // 从内存中获取解析后的数据
    const stockData = getParsedStockData();

    if (stockData.length === 0) {
      return {
        success: false,
        message: '没有数据，请先读取数据文件',
        data: [],
        duplicateGroups: 0,
      };
    }

    console.log(`开始分析 ${stockData.length} 条数据的重复情况...`);

    // 在内存中查找重复数据
    const duplicateMap = new Map();
    const duplicates: any[] = [];

    // 遍历所有数据，按 code + date 分组
    stockData.forEach((item: any) => {
      const key = `${item.code}-${item.date}`;
      if (!duplicateMap.has(key)) {
        duplicateMap.set(key, []);
      }
      duplicateMap.get(key).push(item);
    });

    // 找出重复的数据
    duplicateMap.forEach((items: any[], key: string) => {
      if (items.length > 1) {
        // 添加所有重复的数据
        duplicates.push(...items);
      }
    });

    console.log(
      `在内存中找到 ${duplicates.length} 条重复数据，涉及 ${duplicateMap.size} 个不同的股票日期组合`,
    );

    // 限制返回数量，避免内存溢出
    const limitedDuplicates = duplicates.slice(0, 5000);

    return {
      success: true,
      message: `获取到 ${duplicates.length} 条重复数据，显示前 ${limitedDuplicates.length} 条`,
      data: limitedDuplicates,
      duplicateGroups: duplicateMap.size,
      totalDuplicates: duplicates.length,
      limitedCount: limitedDuplicates.length,
    };
  } catch (error: any) {
    console.error('获取重复数据失败，详细错误信息:', {
      message: error.message,
      stack: error.stack,
    });
    throw error;
  }
}

// 导出函数
export {
  makeUrlsLoop,
  getStockData,
  insertDataToMysql,
  getHousePrice,
  collectLianJiaData,
  testDatabaseConnection,
  createStockDataTable,
  readDataFiles,
  getParsedStockData,
  testInsertData,
  formalInsertData,
  getDuplicateData,
  queryDatabase,
};
